// Copyright (c) Microsoft Corporation. 
// Licensed under the MIT license.

#pragma once

#include "CoreMinimal.h"
#include "Engine/StaticMesh.h"
#include "StandinActor.h"
#include "StandinProxyContainer.generated.h"

class UStaticMesh;

/** A Standin container entry ( an entry would consist of a static mesh, a material and related textures) */
USTRUCT()
struct FStandinProxyEntry
{
	GENERATED_BODY()

		FStandinProxyEntry()
		: StandinActor(nullptr)
		, StaticMesh(nullptr)
		, Material(nullptr)
		, Textures()
		, Key()
	{
	}

#if WITH_EDITOR
	FStandinProxyEntry(AStandInMeshActor* InStandinActor, UStaticMesh* InStaticMesh, UMaterialInterface* InMaterial, const TArray<UTexture2D*>& InTextures, const FName& InKey)
		: StandinActor(InStandinActor)
		, StaticMesh(InStaticMesh)
		, Material(InMaterial)
		, Textures(InTextures)
		, Key(InKey)

	{
	}

	bool operator==(const FStandinProxyEntry& InStandinMesh) const
	{
		return StandinActor == InStandinMesh.StandinActor &&
			   StaticMesh == InStandinMesh.StaticMesh &&
			   Material == InStandinMesh.Material &&
			   Textures == InStandinMesh.Textures &&
			   Key == InStandinMesh.Key;
	}
#endif

	/** Get the mesh for this Standin mesh */
	//const UStaticMesh* GetStaticMesh() const { return StaticMesh; }

	//const UMaterialInterface* GetMaterial() const { return Material; }

	UStaticMesh* GetStaticMesh() const { return StaticMesh; }
	UMaterialInterface* GetMaterial() const { return Material; }

	const TArray<UTexture2D*>& GetTextures() const { return Textures; }

	/** Get the actor for this Standin mesh */
	const TLazyObjectPtr<AStandInMeshActor>& GetStandinActor() const { return StandinActor; }

	/** Get the key for this Standin mesh */
	const FName& GetKey() const { return Key; }

	void Update(UStaticMesh* InStaticMesh, UMaterialInterface* InMaterial, const TArray<UTexture2D*>& InTextures, const FName& InKey)
	{
		StaticMesh = InStaticMesh;
		Material = InMaterial;
		Textures = InTextures;
		Key = InKey;
	}

	void MarkTransient()
	{
		if(StaticMesh)
			StaticMesh->SetFlags(RF_Transient);
		
		if(Material)
			Material->SetFlags(RF_Transient);
		
		for (auto& Texture : Textures)
		{
			if(Texture)
				Texture->SetFlags(RF_Transient);
		}

	}

private:
	/** The Standin that we were generated from */
	UPROPERTY(VisibleAnywhere, Category = "Standin")
	TLazyObjectPtr<AStandInMeshActor> StandinActor;

	/** The mesh used to display this Standin */
	UPROPERTY(VisibleAnywhere, Category = "Standin")
	UStaticMesh* StaticMesh;

	UPROPERTY(VisibleAnywhere, Category = "Standin")
	UMaterialInterface* Material;

	UPROPERTY(VisibleAnywhere, Category = "Standin")
	TArray<UTexture2D*> Textures;

	/** The key generated from an AStandInMeshActor. If this differs from that generated from the AStandInMeshActor, then the mesh needs regenerating. */
	UPROPERTY(VisibleAnywhere, Category = "Standin")
	FName Key;
};

/** This asset acts as a proxy to a static mesh for AStandInMeshActors to display */
UCLASS()
class STANDINACTOR_API UStandinProxyContainer : public UObject
{
	GENERATED_BODY()

public:
#if WITH_EDITOR
	/** Setup the map - only called at initial construction */
	void SetMap(const UWorld* InMap);

    /** Get the owner map for this proxy */
	TSoftObjectPtr<UWorld> GetMap() const;

	/** Adds a static mesh and the key used to generate it */
	void AddStandinProxy(AStandInMeshActor* InStandinActor, UStaticMesh* InStaticMesh, UMaterialInterface* InMaterail, const TArray<UTexture2D*>& InTextures, const FName& InKey);

	/** Clean out invalid proxy mesh entries */
	void Clean();

	void RemoveActorMesh(AStandInMeshActor* InStandinActor);

	void GetUObjectInUseByStandinActor(AStandInMeshActor* InStandinActor,TArray<UObject*>& ExportToOwnPackage);

	virtual void PostLoad() override;
#endif


#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	/** Check if we contain data for the specified actor */
	bool ContainsDataForActor(const AStandInMeshActor* InStandinActor) const;
#endif

private:
#if WITH_EDITORONLY_DATA
	/** Keep hold of the level in the editor to allow for package cleaning etc. */
	UPROPERTY(VisibleAnywhere, Category = "Standins")
	TSoftObjectPtr<UWorld> OwningMap;
#endif

	/** All the mesh proxies we contain */
	UPROPERTY(VisibleAnywhere, Category = "Standins")
	TArray<FStandinProxyEntry> Standins;
};
